﻿using Dapper;
using Dommel;
using Microsoft.Data.SqlClient;
using Microsoft.Extensions.Options;
using System.Data;
using System.Threading.Tasks;
using Loong.Domain.Uow;
using Loong.Threading.Locks.Database;

namespace Loong.Threading.Locks
{
    public class ResourceLockDbAccessor : IResourceLockDbAccessor
    {
        private readonly ConnectionStringOptions _options;

        public ResourceLockDbAccessor(IOptionsMonitor<ConnectionStringOptions> options)
        {
            _options = options.CurrentValue;
        }

        public async Task<ResourceLock> GetByResourceAsync(string resource)
        {
            string sql = "SELECT * FROM dbo.ResourceLock WHERE [Resource]=@resource";

            using (var connection = new SqlConnection(_options.DefaultConnection))
            {
                connection.Open();
                using (var transaction = await connection.BeginTransactionAsync(IsolationLevel.ReadCommitted))
                {
                    ResourceLock resourceLock = await connection.QueryFirstOrDefaultAsync<ResourceLock>(sql, new { resource }, transaction);

                    await transaction.CommitAsync();
                    await connection.CloseAsync();

                    return resourceLock;
                }
            }
        }

        public async Task InsertAsync(ResourceLock resourceLock)
        {
            using (var connection = new SqlConnection(_options.DefaultConnection))
            {
                connection.Open();
                using (var transaction = await connection.BeginTransactionAsync(IsolationLevel.ReadCommitted))
                {
                    await connection.InsertAsync(resourceLock, transaction);

                    await transaction.CommitAsync();
                    await connection.CloseAsync();
                }
            }

        }

        public async Task<bool> UpdateLockAsync(ResourceLock resourceLock)
        {
            string sql = @"
UPDATE dbo.ResourceLock SET
ExpireTime=@ExpireTime,
[Version]=[Version]+1,
LockOwner=@LockOwner
WHERE Id=@Id AND [Version]=@Version
";
            using (var connection = new SqlConnection(_options.DefaultConnection))
            {
                connection.Open();
                using (var transaction = await connection.BeginTransactionAsync(IsolationLevel.ReadCommitted))
                {
                    bool sucess = await connection.ExecuteAsync(sql, resourceLock, transaction) == 1;

                    await transaction.CommitAsync();
                    await connection.CloseAsync();

                    return sucess;
                }
            }

        }

        public bool ReleaseLock(string resource, string lockOwner)
        {
            string sql = "DELETE dbo.ResourceLock WHERE [Resource]=@resource AND LockOwner=@lockOwner";

            using (var connection = new SqlConnection(_options.DefaultConnection))
            {
                connection.Open();
                using (var transaction = connection.BeginTransaction())
                {
                    bool success = connection.Execute(sql, new { resource, lockOwner }, transaction) == 1;

                    transaction.Commit();
                    connection.Close();

                    return success;
                }
            }
        }
    }
}
